#include <linux/kvm_host.h>
#include <linux/types.h>
#include <linux/kvm_host.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/in.h>
#include <linux/list.h>
#include <linux/proc_fs.h>	/* Necessary because we use the proc fs */
#include <linux/seq_file.h>	/* for seq_file */
#include <linux/utsname.h>
#include <linux/spinlock.h>
#include <linux/kmod.h>
#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
#include <asm/types.h>
#include <linux/string.h>
#include "kvm_cache_regs.h"
#include "x86.h"
#include "mmu.h"
#include "kvm_vmi.h"
#include "crumbs_vmx.h"
#include "crumbs.h"

int proc_write(struct kvm_vcpu *vcpu);
int proc_write_helper(struct kvm_vcpu *vcpu, struct fdnode *p, char * syscallname);

extern int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt,
                               gva_t addr, void *val, unsigned int bytes,
                               struct x86_exception *exception);

extern int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
	       gva_t addr, void *val,
	       unsigned int bytes,
	       struct x86_exception *exception);

struct _mydrv_struct *kvm_trace_new;
//static LIST_HEAD (kvm_trace_list); /* List Head */
static LIST_HEAD (kvm_trace_list); /* List Head */
#define system_utsname init_uts_ns.name


int procfile_read(char *page, char **start, off_t offset, int count, int *eof, void *data) {
	//unsigned long flags;
	off_t thischunk_start = 0;
	off_t thischunk_len = 0;
	struct _mydrv_struct *p;

	/* Loop thru the list grabbing device info */
	list_for_each_entry (p, &kvm_trace_list, list) {
	thischunk_len += sprintf (page+thischunk_len, p->info);

	/* Advance thischunk_start only to the extent that the next
	* read will not result in total bytes more than (offset+count)
	*/
	if (thischunk_start + thischunk_len < offset) {
		thischunk_start += thischunk_len;
		thischunk_len = 0;
	} else if (thischunk_start + thischunk_len > offset+count) {
		break;
	} else {
		continue;
		}
	}

	/* Actual start */
	*start = page + (offset - thischunk_start);
	/* Calculate number of written bytes */
	thischunk_len -= (offset-thischunk_start);
	if (thischunk_len > count) {
		thischunk_len = count;
	} else {
		*eof = 1;
		list_del_init(&kvm_trace_list);
	}

	return thischunk_len;
}

int trace_proc_init(struct crumbs_data *crumbs_data)
{
	struct proc_dir_entry *Our_Proc_File;
	char procname[256];
	//strcpy(procname, "kvm-");
	//strcat(procname, crumbs_data->tag);
	strcpy(procname, KVM_TRACE_PROC);

	Our_Proc_File = create_proc_entry(procname, 0777, NULL); //Under the current kernel API, pass NULL for the root of procfs.instead of create_proc_entry, you should use proc_create() with a proper const struct file_operations *.
	if (Our_Proc_File == NULL) {
		remove_proc_entry(procname, NULL);
		printk(KERN_ALERT "Error: Could not initialize %s\n", procname);
		printk(KERN_ALERT "Retry to initialize %s\n", procname);
		Our_Proc_File = create_proc_entry(procname, 0777, NULL);
		//return -1;
	}
	//else
	{
		printk(KERN_ALERT "Add read_proc function\n");
		Our_Proc_File->read_proc=(read_proc_t *) procfile_read;
	}
	return 0;
}
//EXPORT_SYMBOL_GPL(trace_proc_init);

//remove trace proc
int trace_proc_exit(struct crumbs_data *crumbs_data)
{
	struct list_head *pos,*n;
	struct _mydrv_struct *p;

	char procname[256];
	//strcpy(procname, "kvm-");
	//strcat(procname, crumbs_data->tag);
	strcpy(procname, KVM_TRACE_PROC);
	remove_proc_entry(procname, NULL);
	printk(KERN_ALERT "Remove %s\n", procname);
	//list_del_init(&kvm_trace_list);
	list_for_each_safe(pos, n, &(kvm_trace_list))
	{
		p = list_entry(pos, struct _mydrv_struct, list);
		list_del(pos);
		kfree(p);
	}
	if(list_empty(&(kvm_trace_list))) {
		printk("kvm_trace_list for proc %s is empty\n", procname);
	}
	else {
		return -1;
	}
	return 0;
}

int vmx_proc_init()
{
	struct proc_dir_entry *Our_Proc_File;
	char procname[256];

	strcpy(procname, KVM_TRACE_PROC);
	remove_proc_entry(procname, NULL);
	Our_Proc_File = create_proc_entry(procname, 0777, NULL); //Under the current kernel API, pass NULL for the root of procfs.instead of create_proc_entry, you should use proc_create() with a proper const struct file_operations *.
	if (Our_Proc_File == NULL) {
		remove_proc_entry(procname, NULL);
		printk(KERN_ALERT "Error: Could not initialize %s\n", procname);
		printk(KERN_ALERT "Retry to initialize %s\n", procname);
		Our_Proc_File = create_proc_entry(procname, 0777, NULL);
		//return -1;
	}
	else
	{
		printk(KERN_ALERT "Add read_proc function for /proc/%s\n", KVM_TRACE_PROC);
		Our_Proc_File->read_proc=(read_proc_t *) procfile_read;
	}
	return 0;
}

int vmx_proc_exit()
{
	struct list_head *pos,*n;
	struct _mydrv_struct *p;
	//struct file *fp = NULL;
	char filename[256];
	strcpy(filename, "/proc/");
	strcat(filename, KVM_TRACE_PROC);
	printk("kvm_exit, need to delete %s, if it exists\n", filename);
	//if (filp_open(filename, O_RDONLY, 0) == NULL)
	//if (file_open(filename, O_RDWR | O_LARGEFILE, 0) == NULL)
	//{
	//	printk ("The file %s doesn't exist...\n", filename);
	//}
	//else
	{
		printk ("The file %s exist, so delete...\n", filename);
		remove_proc_entry(KVM_TRACE_PROC, NULL);
	}
	list_for_each_safe(pos, n, &(kvm_trace_list))
	{
		printk("delete kvm_trace_list\n");
		p = list_entry(pos, struct _mydrv_struct, list);
		list_del(pos);
		kfree(p);
	}
	if(list_empty(&(kvm_trace_list))) {
		printk("kvm_trace_list for proc %s is empty\n", filename);
	}
	return 0;
}

int any_other_trace(struct kvm_vcpu *vcpu)
{
	/*struct kvm *kvm_pt;
	struct kvm *kvm = vcpu->kvm;
	printk("Iteration on vm_list\n");
	list_for_each_entry(kvm_pt, &(vm_list), vm_list) {
		printk("VM is created at time:%ld.%ld\n", kvm_pt->crumbs_data.tv.tv_sec, kvm_pt->crumbs_data.tv.tv_usec);
		printk("tracing enabled: %d\n", kvm_pt->crumbs_data.running);
	}*/
	struct file* filp = NULL;
	char number[16];

	filp = file_open("/proc/vhost-ctl", O_RDWR | O_LARGEFILE, 0);
	file_read(filp, number, 16, 0);
	printk("vmx:number of active traces: %s\n", number);
	file_close(filp);
	return 0;
}

int crumbs_vmx_selective_syscalls(struct kvm_vcpu *vcpu, char * tag)
{
	unsigned long sys_call_table;
	unsigned long long result;
	struct x86_exception e;

	u64 field_value = -2;
	//sys_call_table =
	kstrtoull(tag, 16, &result);
	//printk("sys_call_table:%016llx\n", result);
	//sys_call_table+SYS_SENDTO*8
	result = result + SYS_SOCKET*(is_long_mode(vcpu) ? 8 : 4);
	//result = result + SYS_SOCKET*8;
	sys_call_table = result & 0xffffffff;
	printk("sys_call_table:%x\n", result);
	kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
			sys_call_table, &(field_value), 8,
			&e);
	printk("socket function:%x\n", field_value);
	kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt,
			result, &field_value, (is_long_mode(vcpu) ? 8 : 4), &e);
			//result, &field_value, 8, &e);
	return 0;
}

int crumbs_vmx_init(struct kvm_vcpu *vcpu, int rate)
{
	//struct fdnode *fdlistnode;
	//struct list_head *pos;
	//struct fdnode *p;
	//int i;

	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	crumbs_data->running = 1;
	crumbs_data->ticket = 0;
	crumbs_data->fdlist_size=0;
	INIT_LIST_HEAD(&(crumbs_data->fdlisthead.list));
	//any_other_trace(vcpu);
	//no need to init proc, since kvm module itself will init a global proc
	//if(trace_proc_init(crumbs_data)!=0)
	//	return -1;
	spin_lock_init(&crumbs_data->proc_lock);
	start_vhost_trace(vcpu->kvm, rate);
	//any_other_trace(vcpu);
	return 0;
}

//cleanup when crumbs is disabled
int crumbs_vmx_exit(struct kvm_vcpu *vcpu)
{
	struct list_head *pos,*n;
	struct fdnode *p;
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	//no need to remove proc,since maybe other VMs are using this proc
	//trace_proc_exit(crumbs_data);
	crumbs_data->running = 0;
	crumbs_data->ticket = 0;
	//list_del_init();
	//empty nodes in fdlist that contains file descriptor
	list_for_each_safe(pos, n, &(crumbs_data->fdlisthead.list))
	{
		p = list_entry(pos, struct fdnode, list);
		list_del(pos);
		kfree(p);
	}
	stop_vhost_trace(vcpu->kvm);
	if(list_empty(&(crumbs_data->fdlisthead.list))) {
		printk("fdlist is empty\n");
		crumbs_data->fdlist_size=0;
		return 0;
	}
	else
		return -1;
}

int dump_fdlist(struct kvm_vcpu *vcpu)
{
	int i=0;
	struct fdnode *p;
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	printk("start dump\n");
	list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
		printk("index:%d,cr3:%ld,esp:%ld,fd:%ld,syscall:%ld\n", i, p->cr3, p->esp, p->fd, p->syscall_number);
		printk("index:%d,ticket:%ld,srcip:%s,srcport:%ld,destip:%s,destport:%ld\n", i, p->ticket, p->srcip, p->srcport, p->destip, p->destport);
		i++;
	}
	printk("end dump\n");
	return 0;
}

int insert_fdlist(struct kvm_vcpu *vcpu)
{
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	crumbs_data->fdnode_new = kmalloc (sizeof (struct fdnode), GFP_ATOMIC);
	if(crumbs_data->fdnode_new!=NULL) {
		do_gettimeofday(&(crumbs_data->fdnode_new->tv));
		crumbs_data->ticket ++;
		crumbs_data->fdnode_new->ticket=crumbs_data->ticket;
		crumbs_data->fdnode_new->cr3=vcpu->arch.cr3;
		crumbs_data->fdnode_new->vcpu_id=vcpu->vcpu_id;
		crumbs_data->fdnode_new->cpu=vcpu->cpu;
		crumbs_data->fdnode_new->esp=kvm_register_read(vcpu, VCPU_REGS_RSP);
		crumbs_data->fdnode_new->fd=0;
		strcpy(crumbs_data->fdnode_new->srcip, "0.0.0.0");
		strcpy(crumbs_data->fdnode_new->destip, "0.0.0.0");
		crumbs_data->fdnode_new->syscall_number=kvm_register_read(vcpu, VCPU_REGS_RAX);
		crumbs_data->fdnode_new->srcport=0;
		crumbs_data->fdnode_new->destport=0;

		list_add_tail (&(crumbs_data->fdnode_new->list), &(crumbs_data->fdlisthead.list));
		crumbs_data->fdlist_size++;
		//printk("insert_fdlist:size:%ld\n", crumbs_data->fdlist_size);
		//dump_fdlist(vcpu);
	}
	else
		return -1;
	return 0;
}

int insert_accept_fdlist(struct kvm_vcpu *vcpu, char * srcip, unsigned long srcport,
		char * destip, unsigned long destport, unsigned ticket, struct timeval tv)
{
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	crumbs_data->fdnode_new = kmalloc (sizeof (struct fdnode), GFP_ATOMIC);
	if(crumbs_data->fdnode_new!=NULL) {
		crumbs_data->fdnode_new->tv.tv_sec=tv.tv_sec;
		crumbs_data->fdnode_new->tv.tv_usec=tv.tv_usec;
		crumbs_data->fdnode_new->ticket=ticket;
		crumbs_data->fdnode_new->cr3=vcpu->arch.cr3;
		crumbs_data->fdnode_new->vcpu_id=vcpu->vcpu_id;
		crumbs_data->fdnode_new->cpu=vcpu->cpu;
		crumbs_data->fdnode_new->esp=kvm_register_read(vcpu, VCPU_REGS_RSP);
		crumbs_data->fdnode_new->fd=0;
		strcpy(crumbs_data->fdnode_new->srcip, srcip);
		strcpy(crumbs_data->fdnode_new->destip, destip);
		crumbs_data->fdnode_new->syscall_number=kvm_register_read(vcpu, VCPU_REGS_RAX);
		crumbs_data->fdnode_new->srcport=srcport;
		crumbs_data->fdnode_new->destport=destport;

		list_add_tail (&(crumbs_data->fdnode_new->list), &(crumbs_data->fdlisthead.list));
		crumbs_data->fdlist_size++;
		printk("insert_accept_fdlist:size:%ld\n", crumbs_data->fdlist_size);
	}
	else
		return -1;
	return 0;
}

//used in is_sysret
int update_fd_fdlist(struct kvm_vcpu *vcpu)
{
	//int i=0;
	struct fdnode *p;
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	//printk("update_fd_fdlist:size:%d\n", crumbs_data->fdlist_size);
	//list_for_each_entry(p, &(crumbs_data->fdlisthead.list), list) {
	//search from the tail, since tail entry has the newest time stamp
	list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
		//if the same thread
		if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)&&p->fd==0)
		{
			if(p->syscall_number==SYS_SOCKET||p->syscall_number==SYS_ACCEPT) {
				//printk("update_fd_fdlist:%d\n", i);
				//i++;
				p->fd=kvm_register_read(vcpu, VCPU_REGS_RAX);
				if(p->syscall_number==SYS_SOCKET)
					proc_write_helper(vcpu, p, "SYS_SOCKET");
					//proc_write(vcpu);
				//if(p->syscall_number==SYS_ACCEPT)
				//	proc_write(vcpu);
				break;
			}
		}
	}
	return 0;
}

//used in is_syscall, for syscall like close
int delete_entry_fdlist(struct kvm_vcpu *vcpu, long fd)
{//dump_fdlist(vcpu);
	int i=0;
	struct list_head *pos,*n;
	struct fdnode *p;
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	//list_for_each_safe(pos, n, &(crumbs_data->fdlisthead.list))
	//search from the tail, since tail entry has the newest time stamp
	list_for_each_prev_safe(pos, n, &(crumbs_data->fdlisthead.list))
	{
		p = list_entry(pos, struct fdnode, list);
		//father and child process can share the same process, so only fd here to compare? or cr3&fd?
		if(p->cr3==vcpu->arch.cr3&&p->fd==fd)
		//if(p->fd==fd)
		{
			i++;
			list_del(pos);
			kfree(p);
			crumbs_data->fdlist_size--;
			//printk("delete_entry_fdlist:%d:size:%ld\n",i, crumbs_data->fdlist_size);
		}
	}
	return 0;
}

char * inet_ntoa(in)
         unsigned long in;
 {
         static char b[18];
         register unsigned char *p;

        p = (unsigned char *)&in;
         sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
         return (b);
}

int open_file_filter(char * filename)
{
	if(strncmp(filename, "/dev/sr0", 8)==0)
		return -1;
	return 0;
}

int proc_write(struct kvm_vcpu *vcpu)
{
	unsigned long rax;
	char syscallname[16];
	long first_argument = 0;
	long second_argument = 0;
	unsigned long flags;
	long long ticket = -1;
	struct timeval tv;
	char srcip[18];
	unsigned long srcport = 0;
	char destip[18];
	unsigned long destport = 0;
	int family;
	struct sockaddr_in serv_addr;
	struct sockaddr_in client_addr;
	struct fdnode *p;
	struct x86_exception e;

	strcpy(srcip, "0.0.0.0");
	strcpy(destip, "0.0.0.0");
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	do_gettimeofday(&tv);
	first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
	rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
	switch(rax)
	{
	case SYS_OPEN:
		strcpy(syscallname, "SYS_OPEN");
		break;
	case SYS_CLOSE:
		strcpy(syscallname, "SYS_CLOSE");
		break;
	case SYS_SOCKET://socket don't have ip or port
		strcpy(syscallname, "SYS_SOCKET");
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same thread and the same sockfd
			if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
					&&p->syscall_number==SYS_SOCKET)
			{
				ticket = p->ticket;
				break;
			}
		}
		break;
	case SYS_ACCEPT:
		strcpy(syscallname, "SYS_ACCEPT");
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
										kvm_register_read(vcpu, VCPU_REGS_RSI),
										(struct sockaddr*)&client_addr, sizeof(struct sockaddr_in), &e);
		strcpy(destip, inet_ntoa(client_addr.sin_addr));
		destport = ntohs(client_addr.sin_port);
		family = client_addr.sin_family;
		printk("proc_write,SYS_ACCEPT,family:%d, destport:%d, destip:%s\n", family, destport, destip);
		//if(family == 2 && destport >0 && strcmp("0.0.0.0", destip) != 0)
		//family value can be other than 2? SYS_ACCEPT,family:34817, destport:65535, destip:8.0.0.0
		//SYS_ACCEPT,family:58432, destport:45870, destip:255.127.0.0
		if(destport >0 && strcmp("0.0.0.0", destip) != 0)
		{//family == AF_INET, so it is ip protocol
			//printk("fd:%ld,src ip address:%s, src port:%ld\n", rax, inet_ntoa(serv_addr.sin_addr), destport);
		}
		else
			return -1;
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same thread and the same sockfd
			if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
					&&p->fd==first_argument&&p->syscall_number==SYS_SOCKET)
			{
				ticket = p->ticket;
				strcpy(srcip, p->srcip);
				srcport=p->srcport;
				break;
			}
		}
		insert_accept_fdlist(vcpu, srcip, srcport, destip, destport, ticket, tv);
		break;
	case SYS_BIND://server bind
		strcpy(syscallname, "SYS_BIND");
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
								kvm_register_read(vcpu, VCPU_REGS_RSI),
								&serv_addr, sizeof(struct sockaddr_in), &e);
		strcpy(srcip, inet_ntoa(serv_addr.sin_addr));
		srcport = ntohs(serv_addr.sin_port);
		family = serv_addr.sin_family;
		if(family == 2 && srcport >0 && strcmp("0.0.0.0", srcip) != 0)
		{//family == AF_INET, so it is ip protocol
			//printk("SYS_BINDfd:%ld,src ip address:%s, src port:%ld\n", first_argument, inet_ntoa(serv_addr.sin_addr), srcport);
		}
		else
			return -1;
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same thread and the same sockfd
			if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
					&&p->fd==first_argument&&p->syscall_number==SYS_SOCKET)
			{
				ticket = p->ticket;
				//update SYS_SOCKET ip and port
				strcpy(p->srcip, srcip);
				p->srcport=srcport;
				break;
			}
		}
		break;
	case SYS_CONNECT://client connect
		strcpy(syscallname, "SYS_CONNECT");
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
								kvm_register_read(vcpu, VCPU_REGS_RSI),
								&serv_addr, sizeof(struct sockaddr_in), &e);
		strcpy(destip, inet_ntoa(serv_addr.sin_addr));
		destport = ntohs(serv_addr.sin_port);
		family = serv_addr.sin_family;
		if(family == 2 && destport >0 && strcmp("0.0.0.0", destip) != 0)
		{//family == AF_INET, so it is ip protocol
			//printk("SYS_CONNECTfd:%ld,dest ip address:%s, dest port:%ld\n", first_argument, inet_ntoa(serv_addr.sin_addr), destport);
		}
		else
			return -1;
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//find latest sys_socket, if the same thread and the same sockfd
			//if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
			//		&&p->fd==first_argument&&p->syscall_number==SYS_SOCKET)
			//find latest sys_socket, if the same process and the same sockfd
			if(p->cr3==vcpu->arch.cr3&&p->fd==first_argument&&p->syscall_number==SYS_SOCKET)
			{
				ticket = p->ticket;
				//update SYS_SOCKET ip and port
				strcpy(p->destip, destip);
				p->destport=destport;
				break;
			}
		}
		break;
	case SYS_LISTEN://only the 1st arg is sockfd
		strcpy(syscallname, "SYS_LISTEN");
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same thread and the same sockfd
			if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
					&&p->fd==first_argument&&p->syscall_number==SYS_SOCKET)
			{
				ticket = p->ticket;
				strcpy(srcip, p->srcip);
				srcport=p->srcport;
				break;
			}
		}
		break;
	case SYS_SENDTO://only the 1st arg is sockfd
		strcpy(syscallname, "SYS_SENDTO");
		//printk("SYS_SENDTO:CR3:%ld:esp:%ld:fd:%ld\n", vcpu->arch.cr3,
				//kvm_register_read(vcpu, VCPU_REGS_RSP), first_argument);
		//dump_fdlist(vcpu);
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same process and the same sockfd
			//if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
			if(p->cr3==vcpu->arch.cr3
					&&p->fd==first_argument)
			{
				if(p->syscall_number==SYS_SOCKET) {//client
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
				if(p->syscall_number==SYS_ACCEPT) {//server
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
			}
		}
		break;
	case SYS_WRITE://only the 1st arg is sockfd
		strcpy(syscallname, "SYS_WRITE");
		//printk("SYS_SENDTO:CR3:%ld:esp:%ld:fd:%ld\n", vcpu->arch.cr3,
				//kvm_register_read(vcpu, VCPU_REGS_RSP), first_argument);
		//dump_fdlist(vcpu);
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same process and the same sockfd
			//if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
			if(p->cr3==vcpu->arch.cr3
					&&p->fd==first_argument)
			{
				if(p->syscall_number==SYS_SOCKET) {//client
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
				if(p->syscall_number==SYS_ACCEPT) {//server
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
			}
		}
		break;
	case SYS_RECVFROM://only the 1st arg is sockfd
		strcpy(syscallname, "SYS_RECVFROM");
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same process/thread and the same sockfd
			//if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
			if(p->cr3==vcpu->arch.cr3
					&&p->fd==first_argument)
			{
				if(p->syscall_number==SYS_SOCKET) {//client
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
				if(p->syscall_number==SYS_ACCEPT) {//server
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
			}
		}
		break;
	case SYS_READ://only the 1st arg is sockfd, similar to SYS_RECVFROM, but read could be non-network fd
		strcpy(syscallname, "SYS_READ");
		list_for_each_entry_reverse(p, &(crumbs_data->fdlisthead.list), list) {
			//if the same process/thread and the same sockfd
			//if(p->cr3==vcpu->arch.cr3&&p->esp==kvm_register_read(vcpu, VCPU_REGS_RSP)
			if(p->cr3==vcpu->arch.cr3
					&&p->fd==first_argument)
			{
				if(p->syscall_number==SYS_SOCKET) {//client
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
				if(p->syscall_number==SYS_ACCEPT) {//server
					ticket = p->ticket;
					strcpy(srcip, p->srcip);
					srcport=p->srcport;
					strcpy(destip, p->destip);
					destport=p->destport;
					break;
				}
			}
		}
		break;
	default:
		printk("System call number not monitored\n");
		break;
	}

	//if find a match, then write to proc, or else don't
	if(ticket>=0) {
	//spin_lock_irqsave(&(vcpu->kvm->crumbs_data.proc_lock), flags);

	kvm_trace_new = kmalloc (sizeof (struct _mydrv_struct), GFP_ATOMIC);
	if(kvm_trace_new!=NULL) {
		//sprintf (kvm_trace_new->info, "(%s)TX:(%d.%d.%d.%d)(%d)(%d.%d.%d.%d)(%d)(%ld.%ld)\n",system_utsname.nodename, firstbyte, secondbyte, thirdbyte, fouthbyte, highbyte*256+lowbyte, firstbyte1, secondbyte1, thirdbyte1, fouthbyte1, highbyte1*256+lowbyte1, tv.tv_sec, tv.tv_usec);
		//sprintf (kvm_trace_new->info, "(%s)(%s)(%s)(%ld)(%s)(%ld)(%s)(%ld)(%ld.%ld)\n",system_utsname.nodename, crumbs_data->tag, syscallname, ticket, srcip, srcport, destip, destport, tv.tv_sec, tv.tv_usec);
		//sprintf (kvm_trace_new->info, "%s:%s:%s:%ld:%s:%ld:%s:%ld:%ld:%ld\n",system_utsname.nodename, crumbs_data->tag, syscallname, ticket, srcip, srcport, destip, destport, tv.tv_sec, tv.tv_usec);
		sprintf (kvm_trace_new->info, "%s_%ld.%ld:%s:%s:%ld:%s:%ld:%s:%ld:%ld:%ld\n",system_utsname.nodename, crumbs_data->tv.tv_sec, crumbs_data->tv.tv_usec, crumbs_data->tag, syscallname, ticket, srcip, srcport, destip, destport, tv.tv_sec, tv.tv_usec);
		//printk ("(%s)(%s)(%s)(%ld)(%s)(%ld)(%s)(%ld)(%ld.%ld)\n",system_utsname.nodename, crumbs_data->tag, syscallname, ticket, srcip, srcport, destip, destport, tv.tv_sec, tv.tv_usec);
		list_add_tail (&kvm_trace_new->list, &kvm_trace_list);
	}
	//spin_unlock_irqrestore(&(vcpu->kvm->crumbs_data.proc_lock), flags);
	}
	return 0;
}

int proc_write_helper(struct kvm_vcpu *vcpu, struct fdnode *p, char * syscallname)
{
	unsigned long rax;
	//char syscallname[16];
	long first_argument = 0;
	long second_argument = 0;
	unsigned long flags;
	unsigned long ticket = 0;
	struct timeval tv;
	char srcip[18];
	unsigned long srcport = 0;
	char destip[18];
	unsigned long destport = 0;
	int family;
	struct sockaddr_in serv_addr;
	struct sockaddr_in client_addr;
	//struct fdnode *p;
	struct x86_exception e;

	strcpy(srcip, "0.0.0.0");
	strcpy(destip, "0.0.0.0");
	struct crumbs_data *crumbs_data = &(vcpu->kvm->crumbs_data);
	//spin_lock_irqsave(&(vcpu->kvm->crumbs_data.proc_lock), flags);

	kvm_trace_new = kmalloc (sizeof (struct _mydrv_struct), GFP_ATOMIC);
	if(kvm_trace_new!=NULL) {
		//sprintf (kvm_trace_new->info, "(%s)TX:(%d.%d.%d.%d)(%d)(%d.%d.%d.%d)(%d)(%ld.%ld)\n",system_utsname.nodename, firstbyte, secondbyte, thirdbyte, fouthbyte, highbyte*256+lowbyte, firstbyte1, secondbyte1, thirdbyte1, fouthbyte1, highbyte1*256+lowbyte1, tv.tv_sec, tv.tv_usec);
		//sprintf (kvm_trace_new->info, "(%s)(%s)(%s)(%ld)(%s)(%ld)(%s)(%ld)(%ld.%ld)\n",system_utsname.nodename, crumbs_data->tag, syscallname, p->ticket, p->srcip, p->srcport, p->destip, p->destport, p->tv.tv_sec, p->tv.tv_usec);
		//sprintf (kvm_trace_new->info, "%s:%s:%s:%ld:%s:%ld:%s:%ld:%ld:%ld\n",system_utsname.nodename, crumbs_data->tag, syscallname, p->ticket, p->srcip, p->srcport, p->destip, p->destport, p->tv.tv_sec, p->tv.tv_usec);
		sprintf (kvm_trace_new->info, "%s_%ld.%ld:%s:%s:%ld:%s:%ld:%s:%ld:%ld:%ld\n",system_utsname.nodename, crumbs_data->tv.tv_sec, crumbs_data->tv.tv_usec, crumbs_data->tag, syscallname, p->ticket, p->srcip, p->srcport, p->destip, p->destport, p->tv.tv_sec, p->tv.tv_usec);

		//printk ("(%s)(%s)(%s)(%ld)(%s)(%ld)(%s)(%ld)(%ld.%ld)\n",system_utsname.nodename, crumbs_data->tag, syscallname, p->ticket, p->srcip, p->srcport, p->destip, p->destport, p->tv.tv_sec, p->tv.tv_usec);
		list_add_tail (&kvm_trace_new->list, &kvm_trace_list);
	}
	//spin_unlock_irqrestore(&(vcpu->kvm->crumbs_data.proc_lock), flags);
	return 0;
}
//EXPORT_SYMBOL_GPL(proc_write_helper);

//for kernel 2.6.x
int is_syscall(struct kvm_vcpu *vcpu)
{
	//unsigned long rax, rbx, idx;
	unsigned long rax;
	u8 filename[256];
	u8 buf[1024];
	struct x86_exception e;
	//network properties
	int family;
	char ip[18];
	long port;
	struct sockaddr_in serv_addr;
	long first_argument = 0;
	long second_argument, third_argument;

	rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
	if(rax == SYS_OPEN) { //open, return int type fd, so need sysret value
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, kvm_register_read(vcpu, VCPU_REGS_RDI), &filename, 256, &e);
		//printk("open: %s\n", filename);
		/*if(open_file_filter(filename)==0) {
			printk("open: %s\n", filename);
			insert_fdlist(vcpu);
		}*/
	}
	if(rax == SYS_READ) {//read, write, first arg is fd
		first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
						kvm_register_read(vcpu, VCPU_REGS_RSI),
						&buf, 1024, &e);
		//printk("read fd:%ld, buf:%s\n", first_argument, buf);
		proc_write(vcpu);
	}
	if(rax == SYS_WRITE) {//read, write, first arg is fd
		first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
						kvm_register_read(vcpu, VCPU_REGS_RSI),
						&buf, 1024, &e);
		//printk("write fd:%ld, buf:%s\n", first_argument, buf);
		proc_write(vcpu);
	}
	if(rax == SYS_SENDMSG || rax == SYS_RECVMSG) {//sendmsg, recvmsg, first arg is fd
		first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		//printk("sendmsg/recvmsg fd:%ld\n", first_argument);
	}
	if(rax == SYS_CLOSE) {//close, first arg is fd
		first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		if(first_argument>=0) {
			delete_entry_fdlist(vcpu, first_argument);
		}
	}
	if(rax == SYS_CONNECT) {//client connect, so dest ip/port
		/*first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
				kvm_register_read(vcpu, VCPU_REGS_RSI),
				&serv_addr, sizeof(struct sockaddr_in), &e);
		strcpy(ip, inet_ntoa(serv_addr.sin_addr));
		port = ntohs(serv_addr.sin_port);
		family = serv_addr.sin_family;
		if(family == 2 && port >0 && strcmp("0.0.0.0", ip) != 0)
		{//family == AF_INET, so it is ip protocol
			printk("SYS_CONNECTfd:%ld,dest ip address:%s, dest port:%ld\n", rax, inet_ntoa(serv_addr.sin_addr), port);
		}*/
		proc_write(vcpu);
	}
	if(rax == SYS_BIND) {//server bind, so src ip/port
		//first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		proc_write(vcpu);
	}
	if(rax == SYS_LISTEN) {//listen, 1st arg is sockfd
		//first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		proc_write(vcpu);
	}
	if(rax == SYS_SOCKET) {//server socket, 1st arg is domain (ip protocol is AF_INET), returns int type sockfd
		first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		if(first_argument==AF_INET) {
			insert_fdlist(vcpu);
			//after get fd value in sysret, do proc_write in is_sysret, not here
		}
	}
	if(rax == SYS_ACCEPT) {//accept, 1st arg is sockfd, returns int type fd
		//printk("is_syscall,SYS_ACCEPT\n");
		//first_argument = kvm_register_read(vcpu, VCPU_REGS_RDI);
		//insert_fdlist(vcpu);
		//though after get fd value in sysret, still do proc_write here
		proc_write(vcpu);
	}
	if(rax == SYS_SENDTO) {
		proc_write(vcpu);
	}
	if(rax == SYS_RECVFROM) {
		proc_write(vcpu);
	}
	return 0;
}
EXPORT_SYMBOL_GPL(is_syscall);

int is_sysret(struct kvm_vcpu *vcpu)
{
	//unsigned long rax, rbx, idx;
	unsigned long rax;
	int ret;
	//struct x86_exception e;
	ret = update_fd_fdlist(vcpu);
	//rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
	return 0;
}
EXPORT_SYMBOL_GPL(is_sysret);
